Skip to content

Engine: stop waiting on a launcher window that does not answer - #265

Merged
hanthor merged 2 commits into
mainfrom
claude/modest-bell-xqa0vv
Oct 1, 2026
Merged

hanthor merged 2 commits into
mainfrom
claude/modest-bell-xqa0vv

Conversation

@hanthor

@hanthor hanthor commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

This fixes the window-slot item in #257.

Problem

serve::forward locks the window slot and awaits WindowLink::push with no time limit. If a launcher window is alive but wedged, every request that needs the window (toggle, show, hide, HUDs, dmenu, deeplinks, launches) waits on that lock until the daemon restarts. Only the CLI had a timeout (10 s).

Change

  • Engine (crates/compass/src/serve.rs): forward now goes through forward_within with WINDOW_ANSWER_TIMEOUT = 30 s. On timeout it answers with an error that names the wait.
  • Why 30 s: the limit bounds a stuck window, not a slow one. A launcher's first Show waits on its renderer, and on a machine without a GPU that takes seconds; it took about 5 s on the wlroots CI runner. The first push used 5 s and failed two Sway tests for exactly this reason.
  • The link is kept on timeout. The window may only be busy, and dropping the link would leave the launcher undriven until it restarts, because the UI does not reattach.
  • Late answers (crates/compass-ipc/src/transport.rs): a window still answers the command the engine gave up on, in order and before the next one. WindowLink::push now skips answers older than its own command id, instead of failing with MismatchedResponse and getting the window dropped. The new # Cancellation doc section explains this. Framed I/O is cancel-safe, so an abandoned write is finished by the next send.
  • No effect on dmenu: every pushed command is answered as soon as the window acts on it. The dmenu choice is awaited outside the push.

Tests

  • compass-ipc, a_push_given_up_on_does_not_steal_the_next_ones_answer: the first push is dropped after 100 ms, the window then answers it late, and the next push reads its own answer. This test fails with the skip removed (control run).
  • compass, window::tests::the_engine_stops_waiting_on_a_slow_window_and_keeps_it: runs through the real bridge. forward_within times out with an error, the slot still holds the link, and after the UI catches up, forward(Hide) is acknowledged.
  • wlroots_engine on local headless Sway: all 16 pass with 30 s. With the limit forced to 200 ms, the two tests that failed in CI fail the same way, which confirms the cause.
  • cargo test -p compass-ipc -p compass passes in full; cargo clippy -p compass-ipc -p compass --all-targets -D warnings is clean; cargo doc with -D warnings is clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn

claude added 2 commits October 1, 2026 20:04
forward() held the window slot for as long as the window took to answer a
pushed command. A wedged window therefore blocked every request that needs
it (toggle, show, HUDs, dmenu, deeplinks) until the daemon restarted; only
the CLI had a timeout.

forward() now gives the window 5 seconds, under the CLI's 10, and answers
with an error naming the wait. The link is kept: the window may only be
busy, and dropping it would leave the launcher undriven until it restarts.
The window still answers the abandoned command in order, so
WindowLink::push now skips answers older than its own command rather than
failing on the mismatched id.

Tests: a dropped push does not steal the next push's answer (compass-ipc,
fails without the skip), and forward_within times out on a slow window,
keeps it, and reads the next answer once it catches up.

Part of #257.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The wlroots track failed on the first Show of two tests: on a runner
without a GPU the new window's renderer took about five seconds to come
up, and the engine gave up on a launcher that was still starting. The
limit is there to bound a stuck window, not a slow one, so it is now
longer than the CLI's 10 seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn

@hanthor-hive-agent hanthor-hive-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks correct to me. forward_within bounds the slot lock and returns an actionable error on timeout (crates/compass/src/serve.rs:2572-2589) without discarding a live window link. The correlation loop then consumes only older late replies before requiring the new command's exact ID (crates/compass-ipc/src/transport.rs:302-328), matching the serialized bridge and the added end-to-end coverage.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.88

@hanthor
hanthor merged commit 2d1b8b7 into main Oct 1, 2026
27 checks passed
@hanthor hanthor mentioned this pull request Oct 1, 2026
6 of 16 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants